;********************************************************************
;*          crt0_demo_arm.s                                         *
;*            Startup Routine (ARMASM)                              *
;*                                                                  *
;*          Copyright (C) 1999-2001 NINTENDO Co.,Ltd.               *
;********************************************************************
    INCLUDE     AgbDefineArm.s
    INCLUDE     AgbMemoryMapArm.s
    INCLUDE     AgbSyscallDefineArm.s
    INCLUDE     AgbMacroArm.s
    AREA        Init, CODE, READONLY

    INCLUDE     MultiSioDefineArm.s

    ENTRY
start
;   INCLUDE     rom_header_arm.s

;--------------------------------------------------------------------
;-                      Reset                                       -
;--------------------------------------------------------------------
    EXTERN      DemoMain
    CODE32
start_vector
        mov     r0, #PSR_IRQ_MODE       ; Switch to IRQ mode
        msr     cpsr, r0
        ldr     sp, sp_irq              ; Set SP_irq
        mov     r0, #PSR_SYS_MODE       ; Switch to system mode
        msr     cpsr, r0
        ldr     sp, sp_usr              ; Set SP_usr
        ldr     r1, =INTR_VECTOR_BUF    ; Set interrupt address
        adr     r0, intr_main
        str     r0, [r1]
        ldr     r1, =DemoMain           ; Start & switch to 16bit code
        mov     lr, pc
        bx      r1
        b       start_vector            ; Reset

    ALIGN
sp_usr  DCD     WRAM_END - 0x100
sp_irq  DCD     WRAM_END - 0x60

;--------------------------------------------------------------------
;-Interrupt Branch Processing(Multiple Interrupts)(Lookup Table) 42-80c -
;--------------------------------------------------------------------
    EXTERN      IntrTable
    GLOBAL      intr_main
    ALIGN
    CODE32
intr_main
        mov     r3, #REG_BASE           ; IE/IF Read
        add     r3, r3, #OFFSET_REG_IE  ; r3: REG_IE
        ldr     r12, [r3]               ; r12: IF|IE

        mrs     r0, spsr                ; Save register (IRQ Mode)
        stmfd   sp!, {r0, r3, r12, lr}  ; {spsr, REG_IE, IF|IE, lr}

        and     r1, r12, r12, lsr #16   ; IE/IF Check
        mov     r2, #0
        ands    r0, r1, #V_BLANK_INTR_FLAG   ; V-Blank Interrupt
        bne     jump_intr
        add     r2, r2, #4

        ands    r0, r1, #SIO_INTR_FLAG | MULTI_SIO_TIMER_INTR_FLAG
        bne     jump_intr                    ; Serial Communication Interrupt
        add     r2, r2, #4                   ; or multi-play communication timer interrupt

        ands    r0, r1, #H_BLANK_INTR_FLAG   ; H-Blank Interrupt
        bne     jump_intr
        add     r2, r2, #4
        ands    r0, r1, #V_COUNT_INTR_FLAG   ; V Counter Interrupt
        bne     jump_intr
        add     r2, r2, #4
        ands    r0, r1, #TIMER1_INTR_FLAG    ; Timer 1 Interrupt
        bne     jump_intr
        add     r2, r2, #4
        ands    r0, r1, #TIMER2_INTR_FLAG    ; Timer 2 Interrupt
        bne     jump_intr
        add     r2, r2, #4
        ands    r0, r1, #TIMER3_INTR_FLAG    ; Timer 3 Interrupt
        bne     jump_intr
        add     r2, r2, #4
        ands    r0, r1, #SIO_INTR_FLAG       ; Serial Communication Interrupt
        bne     jump_intr
        add     r2, r2, #4
        ands    r0, r1, #DMA0_INTR_FLAG      ; DMA0 Interrupt
        bne     jump_intr
        add     r2, r2, #4
        ands    r0, r1, #DMA1_INTR_FLAG      ; DMA1 Interrupt
        bne     jump_intr
        add     r2, r2, #4
        ands    r0, r1, #DMA2_INTR_FLAG      ; DMA2 Interrupt
        bne     jump_intr
        add     r2, r2, #4
        ands    r0, r1, #DMA3_INTR_FLAG      ; DMA3 Interrupt
        bne     jump_intr
        add     r2, r2, #4
        ands    r0, r1, #KEY_INTR_FLAG       ; Key Interrupt
        bne     jump_intr
        add     r2, r2, #4
        ands    r0, r1, #CASSETTE_INTR_FLAG  ; Game Pak Interrupt
loop    bne     loop
jump_intr
        strh    r0, [r3, #2]                    ; Clear IF         23c
                                                    ; Set IE <- Select multiple interrupts
        ldr     r1, =CASSETTE_INTR_FLAG | SIO_INTR_FLAG | MULTI_SIO_TIMER_INTR_FLAG
        and     r1, r1, r12
        strh    r1, [r3]
        mrs     r3, cpsr                            ; Enable multiple interrupts & switch to system mode
        bic     r3, r3, #PSR_CPU_MODE_MASK | PSR_IRQ_DISABLE | PSR_FIQ_DISABLE
        orr     r3, r3, #PSR_SYS_MODE
        msr     cpsr, r3
;---------------------------------------------------------------------System Mode
        ldr     r1, =IntrTable                      ; Jump to User IRG Processing
        add     r1, r1, r2
        ldr     r0, [r1]

        stmfd   sp!, {lr}                           ; Save Register (system mode)
        adr     lr, intr_return                     ; Set Return Address
        bx      r0
intr_return
        ldmfd   sp!, {lr}                           ; Return to register (system mode)

        mrs     r3, cpsr                            ; Disable multiple interrupts & switch to IRQ mode
        bic     r3, r3, #PSR_CPU_MODE_MASK | PSR_IRQ_DISABLE | PSR_FIQ_DISABLE
        orr     r3, r3, #PSR_IRQ_MODE      | PSR_IRQ_DISABLE
        msr     cpsr, r3
;---------------------------------------------------------------------IRQ Mode
        ldmfd   sp!, {r0, r3, r12, lr}          ; Return to register (IRQ mode)
        strh    r12, [r3]                       ; {spsr, REG_IE, IF|IE, lr}
        msr     spsr, r0
        bx      lr                              ; Return to before interrupt


    END

